﻿using System;
using System.Collections.Generic;
using System.Linq;
using NailsFramework.Persistence;
using CID.Domain.Exceptions;

namespace CID.Domain.Infrastructure
{
    public abstract class Template : Model<Template>, ITemplate
    {
        public virtual int Id { get; private set; }
        public virtual string Name { get; set; }
        public virtual string Description { get; set; }
        public virtual bool Enabled { get; set; }
        public virtual bool MultipleServersSupport { get; set; }
        public virtual byte[] Content { get; set; }

        public virtual ITemplateType Type { get; private set; }

        private IList<IParameter> parameters = new List<IParameter>();
        public virtual IEnumerable<IParameter> Parameters { get { return parameters; } }

        public virtual IParameter CreateParameter(string name, string description, ParameterType type)
        {
            var result = new Parameter(name, description, type, this);
            if (parameters.Count(x => result.Name.Equals(x.Name)) > 0) throw new DuplicateChildException(this, result);
            parameters.Add(result);
            return result;
        }

        public virtual void RemoveParameter(IParameter parameter)
        {
            if (parameters.Contains(parameter))
            {
                parameters.Remove(parameter);
                parameter.RemoveFromTemplate();
            }
        }

        public abstract ITemplate CreateCopy();

        protected virtual void CopyMembersTo(ITemplate target)
        {
            target.Enabled = Enabled;
            target.MultipleServersSupport = MultipleServersSupport;
            target.Content = Content;
            foreach (var parameter in Parameters)
                target.CreateParameter(parameter.Name, parameter.Description, parameter.Type);
        }

        protected Template() { }

        internal Template(ITemplateType type, string name, string description, byte[] content) 
        {
            Type = type;
            Name = name;
            Description = description;
            Content = content;
            Enabled = true;
        }

        #region Equals and GetHashCode
        //This class needs to have the Equals overriden to support the comparison with the proxies from the persistence layer
        public override bool Equals(object obj)
        {
            return EntityEqualityHelper.Equals(this, obj);
        }

        public override int GetHashCode()
        {
            return base.GetHashCode();
        }
        #endregion
    }

    public class DeploymentTemplate : Template, IDeploymentTemplate
    {
        protected DeploymentTemplate() : base() { }

        internal DeploymentTemplate(ITemplateType type, string name, string description, byte[] content) : base(type, name, description, content) { }

        public override ITemplate CreateCopy()
        {
            var result = new DeploymentTemplate(Type, String.Empty, String.Empty, Content);
            CopyMembersTo(result);

            return result;
        }
    }

    public class ActivationTemplate : Template, IActivationTemplate
    {
        protected ActivationTemplate() : base() { }

        internal ActivationTemplate(ITemplateType type, string name, string description, byte[] content) : base(type, name, description, content) { }

        public override ITemplate CreateCopy()
        {
            var result = new ActivationTemplate(Type, String.Empty, String.Empty, Content);
            CopyMembersTo(result);

            return result;
        }
    }

    public class DeactivationTemplate : Template, IDeactivationTemplate
    {
        protected DeactivationTemplate() : base() { }

        internal DeactivationTemplate(ITemplateType type, string name, string description, byte[] content) : base(type, name, description, content) { }

        public override ITemplate CreateCopy()
        {
            var result = new DeactivationTemplate(Type, String.Empty, String.Empty, Content);
            CopyMembersTo(result);

            return result;
        }
    }
}
